#pragma once

#include "VertexArray.hpp"

class Mesh {

	friend class ModelNode;

private:

	std::map <GLfloat,VertexArray*,std::less<GLfloat>> levelMap;
	
	void draw();
	
public:

	VertexArray& level(GLfloat distance);
	
	void deleteLevel(GLfloat distance);
	
	void eraseAllLevels();
	
private:

	void _load(FILE* f);
	
public:

	void save(FILE* f);
	
	void load(FILE* f);
	
	bool save(const char* fileName);
	
	bool load(const char* fileName);
	
protected:

	static GLfloat distance;
	
public:

	static void setDistance(GLfloat distance);
	
public:
	
	~Mesh();

};

GLfloat Mesh::distance = 0.0f;

void Mesh::setDistance(GLfloat distance){
	Mesh::distance = distance;
}

bool Mesh::save(const char* fileName){
	FILE *f = fopen(fileName,"wb");
	if (f) {
		save(f);
		fclose(f);
		return true;
	}
	return false;
}
	
bool Mesh::load(const char* fileName){
	FILE* f = fopen(fileName,"rb");
	if (f){
		eraseAllLevels();
		load(f);
		fclose(f);
		return true;
	}
	return false;
}

void Mesh::save(FILE* f){
	GLuint levelCount = levelMap.size();
	fwrite(&levelCount,sizeof(levelCount),1,f);
	for (auto it = levelMap.begin(); it != levelMap.end(); ++it){
		fwrite(&(*it).first,sizeof((*it).first),1,f);
		(*it).second->save(f);
	}
}
	
void Mesh::load(FILE* f){
	eraseAllLevels();
	_load(f);
}

void Mesh::_load(FILE* f){
	GLuint levelCount;
	if (fread(&levelCount,sizeof(levelCount),1,f)!=1){
		printf("file read error\n");
		exit(1);
	}
	for (GLuint i = 0; i < levelCount; i++){
		GLfloat distance;
		if (fread(&distance,sizeof(distance),1,f)!=1){
			printf("file read error\n");
			exit(1);
		}
		level(distance).load(f);
	}
}

void Mesh::draw(){
	if (!levelMap.empty()) {
		for (auto it = levelMap.rbegin(); it != levelMap.rend(); ++it)
			if ((*it).first <= distance) {
				(*it).second->draw();
				return;
			}
		levelMap.begin()->second->draw();	
	}
}

VertexArray& Mesh::level(GLfloat distance){
	auto it = levelMap.find(distance);
	if (it != levelMap.end())
		return *(*it).second;
	VertexArray* va = new VertexArray();
	levelMap[distance] = va;
	return *va;
}

void Mesh::deleteLevel(GLfloat distance){
	for (auto it = levelMap.begin(); it != levelMap.end(); ++it)
		if ((*it).first == distance) {
			delete (*it).second;
			levelMap.erase(it);
			return;
		}
}

void Mesh::eraseAllLevels(){
	for (auto it = levelMap.begin(); it != levelMap.end(); ++it)
		delete (*it).second;
	levelMap.clear();
}

Mesh::~Mesh(){
	eraseAllLevels();
}

